﻿// -- MVC4WPF
// -- Copyright © 2009 Information Control Corporation
// -- Revision History:
// -- Version 0.9.0.0 First codeplex release  - Stephen Giffin

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using System.ComponentModel;


namespace MVC4WPF
{
    /// <summary>
    /// Base class that implements the IWPFControllerWindow interface, and implements the ViewContract property. 
    /// </summary>
    /// <typeparam name="VC">The view contract that this controller manages. This should always be the interface of view contract.</typeparam>
    public abstract class WPFViewWindowControllerBase<VC> : WPFViewControllerBase<VC>, IWPFControllerWindow where VC : IWPFViewWindow
    {
        #region Constructor

        /// <summary>
        /// Base constructor that implements the IControllerViewBase interface
        /// </summary>
        /// <param name="viewContract">The instance of the view contract cast as the views contract interface.</param>
        protected WPFViewWindowControllerBase(VC viewContract)
            : base(viewContract)
        {
            //Initilizing the viewclosing event handler
            SubscribeToViewContractsViewClosingEvent();

            //Subscribing to the view closed event handler on the view.
            SubscribeToEventViewClosed();
        }


        #endregion

        #region IWPFControllerWindow Members

        #region Implementation of event - ViewClosing

        /// <summary>
        /// Local variable that is the event handler for the event 'ViewClosing'.
        /// </summary>
        private CancelEventHandler _viewClosing;

        /// <summary>
        /// Local variable that is the lock object for the event 'ViewClosing', this is included for thread safety.
        /// </summary>
        private object _viewClosingEventLock = new object();

        /// <summary>
        /// This event informs subscribers that the view this controller manages has started the closing process. You can override the closing process in the cancel event args.
        /// </summary>
        event CancelEventHandler IWPFControllerWindow.ViewClosing
        {
            add
            {
                lock (_viewClosingEventLock)
                {
                    _viewClosing += value;
                }
            }

            remove
            {
                lock (_viewClosingEventLock)
                {
                    _viewClosing -= value;
                }
            }
        }

        #endregion

        #region Implementation of event - ViewClosed

        /// <summary>
        /// Local variable that is the event handler for the event 'ViewClosed'.
        /// </summary>
        private EventHandler<EventArgs> _viewClosed;

        /// <summary>
        /// Local variable that is the lock object for the event 'ViewClosed', this is included for thread safety.
        /// </summary>
        private object _viewClosedEventLock = new object();

        /// <summary>
        /// Event that informs subscribers that this controllers view has closed.
        /// </summary>
        event EventHandler<EventArgs> IWPFControllerWindow.ViewClosed
        {
            add
            {
                lock (_viewClosedEventLock)
                {
                    _viewClosed += value;
                }
            }

            remove
            {
                lock (_viewClosedEventLock)
                {
                    _viewClosed -= value;
                }
            }
        }

        #endregion

        /// <summary>
        /// Will inform the view managed by this controller that it needs to show itself.
        /// </summary>
        void IWPFControllerWindow.ShowView()
        {
            ShowControlledView();
        }

        /// <summary>
        /// Will inform the view managed by this controller that it needs to display in a modal dialog view.
        /// </summary>
        /// <param name="parentWindow">The parent window that will own the view.</param>
        void IWPFControllerWindow.ShowViewModal(System.Windows.Window parentWindow)
        {
            ShowControlledViewModal(parentWindow);
        }

        /// <summary>
        /// Will inform the view managed by this controller that it needs to hide.
        /// </summary>
        void IWPFControllerWindow.HideView()
        {
            HideControlledView();
        }

        #endregion

        #region Helper methods for IWPFControllerWindow Members

        #region Subscribing to the ViewContracts - ViewClosed event
        /// <summary>
        /// Helper method that registers the ViewClosed event with a local event handler method.
        /// </summary>
        private void SubscribeToEventViewClosed()
        {
            ViewContract.ViewClosed += new EventHandler<EventArgs>(ViewContract_ViewClosed);
        }

        /// <summary>
        /// Event handler that listens for the ViewClosed event from the view then Ond the ViewClosed event on the controller for other controllers that are listening for the view closed event.
        /// </summary>
        /// <remarks>This method is implemented as virtual so child classes can overload and add additional functionality.</remarks>
        /// <param name="sender">The view that Ond the event.</param>
        /// <param name="e">EventArgs from the hosting view.</param>
        protected virtual void ViewContract_ViewClosed(object sender, EventArgs e)
        {
            //Raising the ViewClosed event on the controller so subscribing controllers are informed the view has closed.
            OnViewClosedEvent(sender, e);
        }

        /// <summary>
        /// Helper method that will send the 'ViewClosed' event if there are any subscribers. This method will invoke the event with a standard invoke.
        /// </summary>
        /// <param name="sender">The source caller of the event.</param>
        /// <param name="e">The event arguments to be Ond with the event.</param>
        protected void OnViewClosedEvent(object sender, EventArgs e)
        {
            if (_viewClosed != null)
            {
                _viewClosed.Invoke(sender, e);
            }
        }

        /// <summary>
        /// Helper method that is to be called  to release the event 'ViewClosed' and supporting resources.
        /// </summary>
        private void ReleaseViewClosedEvent()
        {
            _viewClosed = null;

            _viewClosedEventLock = null;
        }


        /// <summary>
        /// Helper method that releases 
        /// </summary>
        private void ReleaseViewClosedEventSubscription()
        {
            ViewContract.ViewClosed -= ViewContract_ViewClosed;
        }

        #endregion

        #region ViewClosingEvent - Handler and Helpers

        /// <summary>
        /// Helper method that subscribes to the view contracts viewclosing event.
        /// </summary>
        private void SubscribeToViewContractsViewClosingEvent()
        {
            ViewContract.ViewClosing += new System.ComponentModel.CancelEventHandler(ViewContract_ViewClosing);
        }

        /// <summary>
        /// Method that listens for the view closing event on the view contract. This event handler will On the controllers viewclosing event.
        /// </summary>
        /// <param name="sender">View that is closing</param>
        /// <param name="e">Cancel event args from the view. If you set the cancel the view will not close.</param>
        protected virtual void ViewContract_ViewClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            OnViewClosingEvent(sender, e);
        }

        /// <summary>
        /// Helper method that stops listening to the view closing event on the view contract.
        /// </summary>
        private void ReleaseSubscriptionToViewContractsViewClosingEvent()
        {
            ViewContract.ViewClosing -= ViewContract_ViewClosing;
        }

        #endregion

        /// <summary>
        /// Helper method that will raise the 'ViewClosing' event if there are any subscribers. This method will invoke the event with a standard invoke.
        /// </summary>
        /// <param name="sender">The source caller of the event.</param>
        /// <param name="e">The event arguments to be raised with the event.</param>
        protected void OnViewClosingEvent(object sender, CancelEventArgs e)
        {

            if (_viewClosing != null)
            {
                _viewClosing.Invoke(sender, e);
            }
        }

        /// <summary>
        /// Helper method that will release the 'ViewClosing' event and all its assoicated resources.
        /// </summary>
        private void ReleaseViewClosingEvent()
        {
            _viewClosing = null;
            _viewClosingEventLock = null;
        }

        /// <summary>
        /// Will inform the view managed by this controller that it needs to show itself.
        /// This method can be overridden to provide additional logic as needed by implementation.
        /// </summary>
        protected virtual void ShowControlledView()
        {
            ViewContract.ShowView();
        }

        /// <summary>
        /// Will inform the view managed by this controller that it needs to display in a modal dialog view.
        /// This method can be overridden to provide additional logic as needed by implementation.
        /// </summary>
        /// <param name="parentWindow">The parent window that will own the view.</param>
        protected virtual void ShowControlledViewModal(System.Windows.Window parentWindow)
        {
            if (parentWindow != null)
            {
                ViewContract.ShowViewModal(parentWindow);
            }
        }

        /// <summary>
        /// Will inform the view managed by this controller that it needs to hide.
        /// This method can be overridden to provide additional logic as needed by implementation.
        /// </summary>
        protected virtual void HideControlledView()
        {
            ViewContract.HideView();
        }

        #endregion

        #region Override implementation of IDisposable

        /// <summary>
        /// Disposes all managed and unmanaged resources from this class
        /// </summary>
        /// <param name="disposing">Boolean flag the determines if the managed resources are to be disposed</param>
        /// <remarks>This is not thread safe. Dispose should only be called from an owning thread.</remarks>
        protected override void Dispose(bool disposing)
        {

            //Confirming that the class has not already been disposed
            if (!this._disposed)
            {
                try
                {
                    //Determining if managed resources should be release
                    if (disposing)
                    {
                        //Releasing all managed resources
                        DisposeManagedResourcesForWPFViewWindowControllerBase();
                    }

                    //Releasing all unmanaged resources
                    DisposeUnmanagedResourcesForWPFViewWindowControllerBase();

                }
                catch
                {
                    //Swallow dispose exceptions.
                }
                finally
                {
                    //Calling the base classes dispose
                    base.Dispose(disposing);
                }
            }

        }

        #endregion

        #region IDisposable Helper Methods

        /// <summary>
        /// Releases all managed resources from this class.
        /// </summary>
        private void DisposeManagedResourcesForWPFViewWindowControllerBase()
        {
            try
            {
                ReleaseSubscriptionToViewContractsViewClosingEvent();
                ReleaseViewClosingEvent();
                ReleaseViewClosedEvent();
                ReleaseViewClosedEventSubscription();
            }
            catch
            {
                //Swallowing exceptions during dispose.
            }
        }

        /// <summary>
        /// Releases all unmanaged instance based resources.
        /// </summary>
        private void DisposeUnmanagedResourcesForWPFViewWindowControllerBase()
        {
            try
            {
                //No unmanaged resources.
            }
            catch
            {
                //Swallowing exceptions during dispose.
            }
        }
        #endregion
    }
}
